/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package controller;

import digitrencer.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;

/**
 * A modell kezelését végző osztály. Létrehozza a modellt, és megteremti a
 * kapcsolatot a felhasználóval.
 * @author Kéki
 */
public class Controller {

    Model model;
    XMLParser xmlParser;
    CommandInterpreter commandIn;
    PrintWriter logfile;
    ArrayList<Integer> inputs;
    ArrayList<Integer> outputs;

    /**
     * A program belépési pontja, létrehozza a Controllert, és elindítja a fő ciklust.
     * @param args A parncssori paraméterek.
     */
    public static void main(String[] args) {
        Controller controller = new Controller(args);
        controller.mainLoop();
    }

    /**
     * Elvégzi a program inicializálását, létrehozza az xmlParser és commandIn
     * objektumokat, értelmezi a parancssori paramétereket.
     * @param args A paranscsori paraméterek.
     */
    private Controller(String[] args) {                                         //nem kell throws, mivel itt mindent el is kapunk
        try {
            if (args.length == 0) {                                             //default: no logfile, no commandfile
                logfile = null;                                                 //throws FileNotFoundException, SecurityException
                commandIn = new CommandInterpreter(logfile);
            } else if (args.length == 2) {                                      //EGYparaméteres eset
                if (args[0].equals("-out")) {
                    logfile = new PrintWriter(args[1]);                         //throws FileNotFoundException, SecurityException
                    commandIn = new CommandInterpreter(logfile);
                } else if (args[0].equals("-in")) {
                    logfile = new PrintWriter("digitalisRendszerLogfile.txt");//LÉTREHOZ MAGÁNAK FILET HA NINCS?      //throws FileNotFoundException, SecurityException
                    commandIn = new CommandInterpreter(logfile, args[1]);       //throws FileNotFoundException
                } else {
                    throw new IllegalArgumentException("Not supported command line starting command.");
                }
            } else if (args.length == 4) {                                      //KÉTparaméteres eset
                if (args[0].equals("-in") && args[2].equals("-out")) {
                    logfile = new PrintWriter(args[3]);                         //throws FileNotFoundException, SecurityException
                    commandIn = new CommandInterpreter(logfile, args[1]);       //throws FileNotFoundException
                } else if (args[0].equals("-out") && args[2].equals("-in")) {
                    logfile = new PrintWriter(args[1]);                         //throws FileNotFoundException, SecurityException
                    commandIn = new CommandInterpreter(logfile, args[3]);       //throws FileNotFoundException
                } else {
                    throw new IllegalArgumentException("Not supported command line starting command.");
                }
            } else {
                throw new IllegalArgumentException("Not supported command line starting command.");
            }
            inputs = new ArrayList<Integer>();
            outputs = new ArrayList<Integer>();
            xmlParser = new XMLParser(inputs, outputs, logfile);                //throws ParserConfigurationException
        } catch (ParserConfigurationException ex) {     //from xmlParser()
            printMessage("EXCEPTION: " + ex.getMessage() + "\n Program error. The program stopped!");
            System.exit(-1);
            //ex.printStackTrace();
        } catch (FileNotFoundException ex) {            //from CommandInterpreter OR PrintWriter
            //A parancssorban magadott filenév nem létezik.
            printMessage("EXCEPTION: " + ex.getMessage() + "\n Unsupported command line parameters. The program stopped!");
            System.exit(-1);
            //ex.printStackTrace();
        } catch (SecurityException ex) {                 //from PrintWriter
            printMessage("EXCEPTION: " + ex.getMessage() + "\n Eligibility issues. The program stopped!");
            System.exit(-1);
            //ex.printStackTrace();
        } catch (Exception ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            System.exit(-1);
            //ex.printStackTrace();
        }
    }

    /**
     * A program fő ciklusa.
     */
    private void mainLoop() {
        boolean run = true;
        printMessage("Program running, please load a network!");
        while (run) {
            try {
                commandIn.ReadCommand();                                        //throws IOException
                String temp = commandIn.GetCommand();                           //String nem referenciaként adódik át.
                if (temp.equals("load")) {
                    loadXML();
                } else if (temp.compareToIgnoreCase("setSequence") == 0) {
                    setSequence();
                } else if (temp.compareToIgnoreCase("setSwitch") == 0) {
                    setSwitch();
                } else if (temp.compareToIgnoreCase("reset") == 0) {
                    reset();
                } else if (temp.compareToIgnoreCase("step") == 0) {
                    step();
                } else if (temp.compareToIgnoreCase("getOscilloscopeHistory") == 0) {
                    getOscilloscopeHistory();
                } else if (temp.compareToIgnoreCase("getOutputValue") == 0) {
                    getOutputValue();
                } else if (temp.compareToIgnoreCase("getSequence") == 0) {
                    getSequence();
                } else if (temp.compareToIgnoreCase("getInputValue") == 0) {
                    getInputValue();
                } else if (temp.compareToIgnoreCase("exit") == 0) {
                    if (logfile != null) logfile.close();       // Kilépéskor lezárjuk a filet
                    System.exit(0);
                } else {
                    throw new IOException("Unrecognised command: \"" + temp + "\"");
                }
            } catch (IOException ex) {          //A ReadCommand domhatja
                printMessage("EXCEPTION: " + ex.getMessage());
                //ex.printStackTrace();
            }
        }
    }

    /**
     * Kiír egy üzenetet a konzolra és a logfile-ba, amennyiben az létezik.
     * @param message A kiírandó üzenet.
     */
    private void printMessage(String message) {
        System.out.println(message);
        if (logfile != null) {
            logfile.println(message);
        }
    }

    /**
     * Kilistázza a rendszer be- és kimeneteinek értékét.
     * @throws IllegalArgumentException Csak hibás működés esetén fordulhat elő,
     * a getInputValue és a getOutputValue dobhatja.
     */
    private void printIO() throws IllegalArgumentException {     //from getInputValue OR getOutputValue
        String temp;
        for (Integer i : inputs) {                                //bemenetek
            for (boolean b : model.getInputValue(i)) {            //mert ugyebár nem sima booelan-t hanem egy booelan tömböt ad vissza a getInputValue
                if (b) {
                    temp = "1";                              //A boolean értéke kiírva alapesetben "true" és "false" nem pedig "0" és "1"
                } else {
                    temp = "0";
                }
                printMessage("Input #" + i + "\t:\t" + temp);
            }
        }
        for (Integer i : outputs) {                               //kimenetek
            for (boolean b : model.getOutputValue(i)) {           //mert ugyebár nem sima booelan-t hanem egy booelan tömböt ad vissza a getInputValue
                if (b) {
                    temp = "1";                              //A boolean értéke kiírva alapesetben "true" és "false" nem pedig "0" és "1"
                } else {
                    temp = "0";
                }
                printMessage("Output #" + i + "\t:\t" + temp);
            }
        }
    }

    /**
     * Betölti az XML file-t, amit a load parancs paramétereként adtunk meg.
     */
    private void loadXML() {
        try {
            if (commandIn.GetNumberOfParameters() != 1) {
                throw new IllegalArgumentException("Only one word supported after \"load\" command.");
            }
            model = null;
            inputs.clear();
            outputs.clear();
            model = xmlParser.LoadXML(commandIn.GetStringParameter(0)); //LoadXML -> SAXException, IOException, NoSuchFieldException
            //null-t kap karaméterül, ha nem létezik a paramétere. Erre elvben hibát dob és kész.
        } catch (SAXException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IOException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (NoSuchFieldException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IllegalArgumentException ex) {
            //Ez a hiba akkor keltekezik ha a második paraméter nem null, vagyis ha egynél több paramétere van a megadott loadnak, ami nem lehet.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    /**
     * Beállítja a setSequence parancs paramétereként megadott jelgenerátor
     * szekvenciáját a megadott értékre.
     */
    private void setSequence() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 2) {
                throw new IllegalArgumentException("Only two words supported after \"setSequence\" command.");
            }
            model.setSequence(commandIn.GetIntParameter(0), commandIn.GetStringParameter(1));   //IllegalArgumentException NumberFormatException, IndexOutOfBoundsException
            model.run();
            printIO();                                  //throws IllegalArgumentException
        } catch (IllegalArgumentException ex) {  //from SetSequence OR GetIntParameter OR printIO
            //A GetIntParameter NumberFormatException-jét is elkapja, mert leszármazottja kivétel típus
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IndexOutOfBoundsException ex) { //from GetIntParameter OR GetStringParameter
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (UnsupportedOperationException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (UnstableNetworkException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    /**
     * Lekérdezi a getSequence parancs paramétereként megadott jelgenerátor szekvenciáját.
     */
    private void getSequence() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 1) {
                throw new IllegalArgumentException("Only one word supported after \"getSequence\" command.");
            }
            printMessage("Generator #" + commandIn.GetIntParameter(0) + "\t:\t" + model.getSequence(commandIn.GetIntParameter(0))); //NumberFormatException, IndexOutOfBoundsException
        } catch (UnsupportedOperationException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IndexOutOfBoundsException ex) { //from GetIntParameter OR GetStringParameter
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IllegalArgumentException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    //by Gergő
    /**
     * Átbillenti a setSwitch paramétereként megadott kapcsolót.
     */
    private void setSwitch() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 1) {
                throw new IllegalArgumentException("Only one word supported after \"setSwitch\" command.");
            }
            model.setSwitch(commandIn.GetIntParameter(0));   //IllegalArgumentException NumberFormatException, IndexOutOfBoundsException
            model.run();
            printIO();                                          //throws IllegalArgumentException
        } catch (IllegalArgumentException ex) {  //from SetSequence OR GetIntParameter OR printIO
            //A GetIntParameter NumberFormatException-jét is elkapja, mert leszármazottja kivétel típus
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IndexOutOfBoundsException ex) { //from GetIntParameter OR GetStringParameter
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (UnsupportedOperationException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (UnstableNetworkException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    /**
     * Visszaállítja a rendszert az alapállapotba.
     */
    private void reset() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 0) {      //A reset parancsnak nincs paramétere
                throw new IllegalArgumentException("No word supported after \"reset\" command.");
            }
            model.reset();
            printIO();                                          //throws IllegalArgumentException
        } catch (UnsupportedOperationException ex) {
            //Nincs még model.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IllegalArgumentException ex) {      //elkapja a NumberFormatException-t is
            //a "reset" után még van valami gépelve az utasításban.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    /**
     * Lépteti a rendszerben található összes jelgenerátort.
     */
    private void step() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 0) {      //A step parancsnak nincs paramétere
                throw new IllegalArgumentException("No word supported after \"step\" command.");
            }
            model.stepGenerators();
            model.run();
            printIO();                                          //throws IllegalArgumentException
        } catch (UnsupportedOperationException ex) {
            //Nincs még model.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IllegalArgumentException ex) {      //elkapja a NumberFormatException-t is
            //a "step" után még van valami gépelve az utasításban.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (UnstableNetworkException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    //by Gergő - egy az egyben a 2 utána következő
    /**
     * Lekérdezi a getOsciloscopeHistory parancs paramétereként megadott
     * oszcilloszkóp által tárolt jelsorozatot.
     */
    private void getOscilloscopeHistory() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 1) {      //A getOscilloscopeHistory parancsnak csak egy paramétere van
                throw new IllegalArgumentException("Only one word supported after \"getOscilloscopeHistory\" command.");
            }
            String stemp = "";
            for (boolean i : model.getOscilloscopeHistory(commandIn.GetIntParameter(0))) {  //A ciklus kipróbálra és a várt Stringet produkálja
                if (i) {                                                                    //NumberFormatException, IndexOutOfBoundsException
                    stemp += 1;
                } else {
                    stemp += 0;
                }
            }
            printMessage("Oscilloscope #" + commandIn.GetIntParameter(0) + "\t:\t" + stemp);
        } catch (UnsupportedOperationException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IllegalArgumentException ex) {      //elkapja a NumberFormatException-t is
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IndexOutOfBoundsException ex) {
            //a GetIntParameter dobja, ha túlindekszeljük, de ilyen úgyse lesz.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    //by Gergő - szinte egy az egyben a getInputValue másolata
    /**
     * Lekérdezi a getOutputValue parancs paramétereként megadott kimenet értékét.
     */
    private void getOutputValue() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 1) {      //A getOutputValue parancsnak csak egy paramétere van
                throw new IllegalArgumentException("Only one word supported after \"getOutputValue\" command.");
            }
            String stemp = "";
            for (boolean i : model.getOutputValue(commandIn.GetIntParameter(0))) {   //A ciklus kipróbálra és a várt Stringet produkálja
                if (i) {                                                             //NumberFormatException, IndexOutOfBoundsException
                    stemp += 1;
                } else {
                    stemp += 0;
                }
            }
            printMessage("Output #" + commandIn.GetIntParameter(0) + "\t:\t" + stemp);
        } catch (UnsupportedOperationException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IllegalArgumentException ex) {      //elkapja a NumberFormatException-t is
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IndexOutOfBoundsException ex) {
            //a GetIntParameter dobja, ha túlindekszeljük, de ilyen úgyse lesz.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }

    /**
     * Lekérdezi a getInputValue parancs paramétereként megadott bemenet értékét.
     */
    private void getInputValue() {
        try {
            if (model == null) {
                throw new UnsupportedOperationException("This command is not supported, until a network is loaded.");
            }
            if (commandIn.GetNumberOfParameters() != 1) {      //A getInputValue parancsnak csak egy paramétere van
                throw new IllegalArgumentException("Only one word supported after \"getInputValue\" command.");
            }
            String stemp = "";
            for (boolean i : model.getInputValue(commandIn.GetIntParameter(0))) {   //A ciklus kipróbálva és a várt Stringet produkálja
                if (i) {                                                            //NumberFormatException, IndexOutOfBoundsException
                    stemp += 1;
                } else {
                    stemp += 0;
                }
            }
            printMessage("Input #" + commandIn.GetIntParameter(0) + "\t:\t" + stemp);
        } catch (UnsupportedOperationException ex) {
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IllegalArgumentException ex) {      //elkapja a NumberFormatException-t is
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        } catch (IndexOutOfBoundsException ex) {
            //a GetIntParameter dobja, ha túlindekszeljük, de ilyen úgyse lesz.
            printMessage("EXCEPTION: " + ex.getMessage());
            //ex.printStackTrace();
        }
    }
}
